<script setup lang="ts">
// import exampleImage from "@/common/assets/images/aaa.jpg"
import { fabric } from "fabric"
import { uniqBy } from "lodash-es"
import { computed, ref } from "vue"
import { getRandomColor } from "./color"

interface Props {
  isEdit: boolean
  imgUrl: string
}
const props = defineProps<Props>()
const emits = defineEmits(["mouseUp", "mouseDown"])
let backgroundImage: any
const canEdit = computed(() => {
  return props.isEdit
})


let globalColor = ""
let globalText = ""
let isCurrentNameHight = false

let canvas: any
const normalizedCoordinatesList = ref<any[]>([])

const isDark = ref(false)

watch(
  () => canEdit.value,
  (newVal) => {
    const filterData = getRectFilterData()
    filterData.forEach((item: any) => {
      item.selectable = newVal
      item.hoverCursor = newVal ? "move" : "default"
    })
    canvas.renderAll()
  }
)

function loadImage(imgUrl: string): Promise<any> {
  canvas.clear()
  const parent = document.getElementById("ft-canvas")
  const parentHeight = parent?.clientHeight || 800
  return new Promise((resolve) => {
    console.log(imgUrl, "imgUrl")
    fabric.Image.fromURL(imgUrl, (img: any) => {
      const canvasWidth = (img.width / img.height) * parentHeight
      const canvasHeight = 800
      console.log(canvasWidth, canvasHeight, "canvasWidth")
      canvas.setWidth(canvasWidth)
      canvas.setHeight(canvasHeight)
      backgroundImage = img
      img.lockUniScaling = true
      img.scaleToWidth(canvasWidth)
      img.scaleToHeight(canvasHeight)
      img.set({
        evented: false // 禁止图片响应事件
      })
      canvas.add(img)
      canvas.sendToBack(img) // 将图片置于底层
      canvas.renderAll()
      resolve({
        img,
        canvasWidth,
        canvasHeight
      })
    }, {
      crossOrigin: "anonymous"
    })
  })
}

// 初始化画布
async function initCanvas(imgUrl: string) {
  const cnv = document.getElementById("canvas") as HTMLCanvasElement
  if (!cnv) {
    console.error("未找到 canvas 元素")
    return
  }
  if(canvas){
    canvas.clear() // 清空画布
    canvas.remove(backgroundImage) // 移除背景图片
    canvas.dispose() // 销毁之前的画布实例
    canvas = null
  }
  canvas = new fabric.Canvas(cnv, {
    perPixelTargetFind: false, // 开启逐像素目标查找
    selection: false, // 禁用默认的选择行为
    backgroundColor: "#fff"
  })
  await loadImage(imgUrl)
  enableRectInteraction(canvas.getWidth(), canvas.getHeight())
  canvas.on("object:scaling", (e: any) => {
    const obj = e.target
    if (obj instanceof fabric.Rect) {
      // 计算矩形新的宽度和高度
      activeRectNormalized()
      if (isDark.value) {
        highlight()
      }
    }
  })
  canvas.on("object:moving", () => {
    if (isDark.value) {
      const objects = canvas.getObjects()
      const filterData = objects.filter((item: any) => {
        return item.get("type") === "rect" && item.normCoords && item.normCoords.split(" ")[0] === globalText
      })
      if (isCurrentNameHight) {
        handleClearDark()
        isDark.value = true
        highlight(filterData)
      } else {
        highlight()
      }
    }
    activeRectNormalized()
  })
}

// 判断点是否在矩形内
function isPointInRect(point: any, rect: any) {
  const { x, y } = point
  const { left, top, width, height, scaleX, scaleY } = rect
  return x >= left && x <= left + width * scaleX && y >= top && y <= top + height * scaleY
}

// 启用矩形框选和移动功能
function enableRectInteraction(canvasWidth: any, canvasHeight: any) {
  // const canvasWidth = canvas.getWidth()
  // const canvasHeight = canvas.getHeight()
  console.log(canvasWidth, canvasHeight, "canvasWidth")
  let isDrawing = false
  let startPoint: any
  let rect: any
  let isMoving = false

  canvas.on("mouse:down", (options: any) => {
    const pointer = options.absolutePointer
    console.log("鼠标按下位置:", options)
    emits("mouseDown", options)
    const objects = canvas.getObjects()
    for (let i = objects.length - 1; i >= 0; i--) {
      const obj = objects[i]
      if (obj.get("type") === "rect" && isPointInRect(pointer, obj)) {
        isMoving = true
        startPoint = pointer
        break
      }
    }

    if (!isMoving) {
      if (!canEdit.value) return // 如果不可编辑，直接返回
      if (options.transform && (["scale", "scaleY", "scaleX"].includes(options.transform.action))) return // 如果是缩放操作，直接返回
      if (isDark.value) return
      isDrawing = true
      startPoint = pointer
      if (options.target && options.target.fill === "transparent") {
        // 如果点击的是透明矩形，直接返回
        return
      }
      const filterData = getRectFilterData()
      if (filterData.length > 0) {
        const lastTargetData = filterData[filterData.length - 1] as any
        globalText = lastTargetData.normCoords.split(" ")[0]
        globalColor = lastTargetData.stroke
      }
      const color = globalColor || getRandomColor()
      rect = new fabric.Rect({
        left: startPoint.x,
        top: startPoint.y,
        width: 0,
        height: 0,
        fill: "transparent",
        stroke: color,
        strokeWidth: 2
      })
      canvas.bringToFront(rect) // 将矩形置于顶层
    }
  })

  canvas.on("mouse:move", (options: any) => {
    const pointer = options.absolutePointer
    if (isDrawing && rect) {
      rect.set({
        width: Math.abs(pointer.x - startPoint.x),
        height: Math.abs(pointer.y - startPoint.y),
        left: Math.min(startPoint.x, pointer.x),
        top: Math.min(startPoint.y, pointer.y)
      })
      rect.hoverCursor = "move"
    }

    canvas.renderAll()
  })

  canvas.on("mouse:up", (options: any) => {
    if (isDrawing) {
      if (rect && rect.width > 0 && rect.height > 0) {
        console.log(canvasWidth, canvasHeight, "canvasWidth")
        const normX1 = rect.left / canvasWidth
        const normY1 = rect.top / canvasHeight
        const normX2 = (rect.left + rect.width * rect.scaleX) / canvasWidth
        const normY2 = (rect.top + rect.height * rect.scaleY) / canvasHeight
        const normCoords = `${globalText || "ft"} ${normX1} ${normY1} ${normX2} ${normY2}`
        normalizedCoordinatesList.value.push(normCoords)
        rect.normCoords = normCoords
        globalColor = rect.stroke
        canvas.add(rect)
        canvas._setActiveObject(rect)
        console.log("归一化坐标:", normalizedCoordinatesList.value)
      }
      console.log("isMoving:", isMoving, isDrawing)
      rect = null
    }
    emits("mouseUp", options)

    isDrawing = false
    isMoving = false
    canvas.renderAll()
  })

  // 防止对象组合
  canvas.on("selection:created", (e: any) => {
    if (e.target && e.target.get("type") === "group") {
      canvas.discardActiveObject()
    }
  })
}

function setActiveObjectByName(name: string) {
  // highlight()
  const objects = canvas.getObjects()
  const filterData = objects.filter((item: any) => {
    return item.get("type") === "rect" && item.normCoords && item.normCoords.split(" ")[0] === name
  })
  isCurrentNameHight = true
  handleClearDark()
  isDark.value = true
  highlight(filterData)
  console.log(filterData, "filterData")
}

function activeRectNormalized() {
  const canvasWidth = canvas.getWidth()
  const canvasHeight = canvas.getHeight()
  const activeObject = canvas.getActiveObject()
  if (activeObject) {
    const normCoords = activeObject.normCoords
    if (normCoords) {
      const normX1 = activeObject.left / canvasWidth
      const normY1 = activeObject.top / canvasHeight
      const normX2 = (activeObject.left + activeObject.width * activeObject.scaleX) / canvasWidth
      const normY2 = (activeObject.top + activeObject.height * activeObject.scaleY) / canvasHeight
      const name = normCoords.split(" ")[0]
      const normCoordsArr = `${name} ${normX1} ${normY1} ${normX2} ${normY2}`
      normalizedCoordinatesList.value = normalizedCoordinatesList.value.map((item) => {
        if (item.split(" ")[0] === name) {
          return normCoordsArr
        }
        return item
      })
      activeObject.normCoords = normCoordsArr
    }
  }
}

function transformNormCoords(normCoords: string) {
  const parts = normCoords.split(" ")
  const name = parts[0]
  const normX1 = Number.parseFloat(parts[1])
  const normY1 = Number.parseFloat(parts[2])
  const normX2 = Number.parseFloat(parts[3])
  const normY2 = Number.parseFloat(parts[4])
  return {
    name,
    normX1,
    normY1,
    normX2,
    normY2
  }
}

function getNormCoordsColorMap(rectData: any[]) {
  const normCoordsColorMap: any = {}
  rectData.forEach((item: any) => {
    const normCoords = item.normCoords
    if (normCoords) {
      const parts = normCoords.split(" ")
      const name = parts[0]
      const color = item.stroke
      normCoordsColorMap[name] = color
    }
  })
  return normCoordsColorMap
}

// 根据归一化坐标绘制矩形
function drawRectanglesFromNormalized(arr: any[], rectData: any[]) {
  const canvasWidth = canvas.getWidth()
  const canvasHeight = canvas.getHeight()
  normalizedCoordinatesList.value = arr
  console.log(canvasWidth, canvasHeight, "canvasWidth")
  const normCoordsColorMap = getNormCoordsColorMap(rectData)
  console.log(normCoordsColorMap, "normCoordsColorMap")
  for (let i = 0; i < normalizedCoordinatesList.value.length; i++) {
    const normCoords = normalizedCoordinatesList.value[i]
    const { name, normX1, normY1, normX2, normY2 } = transformNormCoords(normCoords)
    console.log(normX1, "normX1normX1normX1")
    const left = normX1 * canvasWidth
    const top = normY1 * canvasHeight
    const width = (normX2 - normX1) * canvasWidth
    const height = (normY2 - normY1) * canvasHeight
    const color = normCoordsColorMap[name] || getRandomColor()
    const rect = new fabric.Rect({
      left,
      top,
      width,
      height,
      stroke: color,
      strokeWidth: 2,
      fill: "transparent"
    }) as any
    rect.normCoords = normCoords
    rect.hoverCursor = "move"
    canvas.add(rect)
    canvas.bringToFront(rect)
    canvas.add(rect)
  }
}

function highlight(currentData?: any[]) {
  // 移除之前添加的遮盖层
  const data = currentData || canvas.getObjects()
  data.forEach((obj: any) => {
    if (obj !== backgroundImage && obj.fill !== "transparent") {
      canvas.remove(obj)
    }
  })

  const canvasWidth = canvas.getWidth()
  const canvasHeight = canvas.getHeight()

  // 构建路径字符串（大矩形 + 两个排除区域）
  let pathStr = `M0 0 L${canvasWidth} 0 L${canvasWidth} ${canvasHeight} L0 ${canvasHeight} Z `
  const filterData = uniqBy(data, "left").filter((item: any) => {
    return item.fill === "transparent"
  })
  // 添加两个矩形排除区域
  filterData.forEach((rect: any) => {
    const left = rect.left
    const top = rect.top
    const width = rect.width * rect.scaleX
    const height = rect.height * rect.scaleY
    pathStr += `M${left} ${top} L${left + width} ${top} L${
      left + width
    } ${top + height} L${left} ${top + height} Z `
  })

  // 创建带排除区域的遮盖层
  const overlay = new fabric.Path(pathStr, {
    fill: "rgba(0, 0, 0, 0.5)",
    fillRule: "evenodd", // 关键：使用奇偶填充规则
    selectable: false,
    evented: false // 禁止交互
  })

  canvas.add(overlay)

  // 将原始矩形置于遮盖层上方
  filterData.forEach((rect: any) => {
    canvas.bringToFront(rect)
  })

  canvas.renderAll()
}

function handleDark() {
  isDark.value = true
  isCurrentNameHight = false
  highlight()
}

function handleClearDark() {
  isDark.value = false
  const data = canvas.getObjects()
  data.forEach((obj: any) => {
    if (obj !== backgroundImage && obj.fill !== "transparent") {
      canvas.remove(obj)
    }
  })
  canvas._activeObject = null
  canvas.renderAll()
}

function getRectData() {
  const data = canvas.getObjects()
  return data
}

function getRectFilterData() {
  const data = getRectData()
  const filterData = uniqBy(data, "left").filter((item: any) => {
    return item.fill === "transparent"
  })
  return filterData
}

function setGlobalText(text: string) {
  globalText = text
}

function setActiveObjectName(name: string) {
  const activeObject = canvas.getActiveObject()
  const normCoords = activeObject.normCoords
  const normCoordsArr = normCoords.split(" ")
  const currentActiveObjectName = normCoordsArr[0]
  if (currentActiveObjectName !== name) {
    normCoordsArr[0] = name
    activeObject.normCoords = normCoordsArr.join(" ")
    activeObject.set("stroke", getRandomColor())
    activeObject.set("strokeUniform", true)
    canvas.renderAll()
  }
}

function getActiveObject() {
  const activeObject = canvas.getActiveObject()
  if (activeObject) {
    return activeObject
  } else {
    console.log("没有选中的对象")
    return null
  }
}

function deleteMultiRect(name: string) {
  const objects = canvas.getObjects()
  const filterData = objects.filter((item: any) => {
    return item.get("type") === "rect" && item.normCoords && item.normCoords.split(" ")[0] === name
  })
  filterData.forEach((item: any) => {
    canvas.remove(item)
  })
  canvas.renderAll()
}

function setSelectable(selectable: boolean) {
  const objects = getRectFilterData()
  objects.forEach((item: any) => {
    console.log(item, "item")
    item.selectable = selectable
    item.hoverCursor = selectable ? "move" : "default"
  })
}

defineExpose({
  highlight,
  handleDark,
  handleClearDark,
  getRectData,
  drawRectanglesFromNormalized,
  initCanvas,
  getActiveObject,
  setGlobalText,
  setActiveObjectByName,
  setActiveObjectName,
  deleteMultiRect,
  setSelectable,
  loadImage
})
</script>

<template>
  <div class="ft-canvas" id="ft-canvas">
    <canvas id="canvas" />
  </div>
</template>

<style>
.ft-canvas {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

#canvas {
  width: 700px;
  height: 700px;
  margin: auto;
}
.canvas-container {
  margin: 0 auto !important;
}
</style>
